<template>
  <div
      ref="containerRef"
      class="map-container"
      style="width: 100%; height: 100%"
      v-loading="loading"
      @click="handleClick"
  >
    <!-- Three.js 场景会在这个容器中渲染 -->
    <div class="tooltip" ref="tooltipRef"></div>
  </div>
</template>

<script setup>
import axios from "axios";
import {ref, onMounted, onBeforeUnmount, watch} from "vue";
import * as THREE from "three";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
import {geoMercator} from "d3-geo";
import LightSweepMaterial from "../../utils/lightSweepMaterial.js";
import {RGBELoader} from "three-stdlib";
import {TextGeometry} from "three/examples/jsm/geometries/TextGeometry.js";
import {FontLoader} from "three/examples/jsm/loaders/FontLoader.js";
import {
  CSS2DObject,
  CSS2DRenderer,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
import {mergeGeometries} from "three/examples/jsm/utils/BufferGeometryUtils.js";
import {set} from "lodash";

// 全局变量
let jsondata = null;
let camera = null;
let scene = null;
let renderer = null;
let controls = null;
let map = null;
let midMap = null;
let baseMap = null;
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
let lastPick = null;
let lightMesh = null;
let lightMaterial = null;
let gridHelper = null;
let labelRenderer = new CSS2DRenderer();
let cameraModelCss2dGroup = [];
const ringWidth = 0.1;
const T = Math.PI / 2;
let aCoordinate = [104.0, 37.5];
let scale = 40;
const loading = ref(true);
let projectionFn = geoMercator()
    .center(aCoordinate)
    .scale(scale)
    .translate([0, 0]);

// setup function variables
const containerRef = ref(null);
const tooltipRef = ref(null);
const mapInitPosition = {x: 0, y: 6, z: 0};
const mapDepth = 6;
const isAnimating = ref(true);
// 地图放大倍率
const MapScale = {
  province: 100,
  city: 200,
  district: 300,
};
// 在组件的 data 或 setup 中定义一个全局 scale 变量
let fixedRandomFactor = null;
const props = defineProps({
  adcode: {type: String, default: ""},
  mapData: {type: Object, default: null},
});
watch(props, () => {
  resetInitMap();
  // fetchMapData(props.adcode);
  setCenterAndScale(props.mapData);
});

// 清除之前地图
const resetInitMap = () => {
  loading.value = true;
  cameraModelCss2dGroup.forEach((label) => {
    scene.remove(label); // 从场景中移除标签
    if (label.element && label.element.parentNode) {
      label.element.parentNode.removeChild(label.element); // 从 DOM 中移除
    }
  });
  cameraModelCss2dGroup.length = 0; // 清空标签数组
  scene.remove(map);
  scene.remove(midMap);
  scene.remove(baseMap);
};

const getCameraPositon = () => {
  console.log(camera.position.x);
  console.log(camera.position.y);
  console.log(controls.target);
};
const initializeThree = () => {
  const width = containerRef.value.clientWidth;
  const height = 500;

  // 创建场景
  scene = new THREE.Scene();
  scene.background = new THREE.Color("#ffffff");

  // 创建相机
  camera = new THREE.PerspectiveCamera(30, width / height, 0.1, 1000);

  // var newPosition = new THREE.Vector3(0.17, 3.55, 20);
  // camera.position.set(0, 0, 20);
  camera.position.set(0, -20, 80);

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setSize(width, height);

  // 将渲染器的DOM元素（canvas）添加到容器中
  containerRef.value.appendChild(renderer.domElement);

  // 添加控制器
  controls = new OrbitControls(camera, renderer.domElement);
  // controls.target = new THREE.Vector3(0.667, 7.8, 0.2);
  // 使用 RGBELoader 加载 HDR 环境贴图
  const loader = new RGBELoader();
  loader.load("http://47.105.210.118:10005/json/umhlanga_sunrise_1k.hdr", function (texture) {
    texture.mapping = THREE.EquirectangularReflectionMapping;
    scene.environment = texture;
  });

  // 添加扩散圈
  const geometry = new THREE.PlaneGeometry(290, 290);
  lightMaterial = new LightSweepMaterial();
  lightMesh = new THREE.Mesh(geometry, lightMaterial);
  scene.add(lightMesh);

  // 添加网格
  gridHelper = new THREE.GridHelper(2000, 100, "#bbb", "#bbb");
  gridHelper.rotation.x = -Math.PI / 2;
  gridHelper.position.set(0, -0.01, 0);
  scene.add(gridHelper);

  // 加载地图数据
  loadMapData();
  // fetchMapData(540000);

  // 初始化 labelRenderer
  initLabelRenderer();

  // 开始渲染循环
  animate();
};

// 初始化 labelRenderer
const initLabelRenderer = () => {
  const width = containerRef.value.clientWidth;
  const height = 500;
  labelRenderer.domElement.style.position = "absolute";
  labelRenderer.domElement.style.top = "0px";
  labelRenderer.domElement.style.pointerEvents = "none";
  labelRenderer.setSize(width, height);
  containerRef.value.appendChild(labelRenderer.domElement);
};
// 加载地图数据的逻辑
const loadMapData = () => {
  const loader = new THREE.FileLoader();
  loader.load("http://47.105.210.118:10005/json/ChinaMap.json", (data) => {
    jsondata = JSON.parse(data);
    createMap(jsondata);
    createMidMap(jsondata);
    createBaseMap(jsondata);
  });
};
// 在线加载地图数据
const fetchMapData = async (code) => {
  try {
    const response = await axios.get(
        `https://geo.datav.aliyun.com/areas_v3/bound/${code}_full.json`
    );
    jsondata = response.data;
    createMap(jsondata);
    createMidMap(jsondata);
    createBaseMap(jsondata);
  } catch (error) {
    console.error("Error fetching map data:", error);
  }
};

// 动态获取地图缩放比例
const applyDynamicMapScale = (mapObject3D) => {
  const width = containerRef.value.clientWidth;
  const height = containerRef.value.clientHeight;
  const refArea = width * height;
  const boundingBox = new THREE.Box3().setFromObject(mapObject3D);
  const size = new THREE.Vector3();
  boundingBox.getSize(size);
  // 如果 fixedRandomFactor 为空，则首次生成随机数，否则复用已生成的随机数
  if (fixedRandomFactor === null) {
    fixedRandomFactor = parseFloat((Math.random() + 0.5).toFixed(2));
  }
  const scale =
      Math.round(Math.sqrt(refArea / (size.x * size.y * 400))) +
      fixedRandomFactor;
  console.log(scale);
  mapObject3D.scale.set(scale, scale, 1);
};

// 设置中心点及缩放
const setCenterAndScale = (data) => {
  console.log(data);
  aCoordinate = data.centroid || data.center;
  scale = MapScale[data.level];
  fetchMapData(data.adcode);
  if (data.level == "district") {
    return;
  }
};

// 创建顶部地图
const createMap = (data) => {
  // 创建地图对象
  map = new THREE.Object3D();
  const projection = getProjection();

  // 获取数据中的最大值
  const maxFeatureValue = Math.max(
      ...data.features
          .map((elem) => elem.properties.subFeatureIndex)
          .filter((value) => typeof value === "number" && !isNaN(value))
  );

  // 辅助方法1: 生成材质配置
  const getMaterialConfig = (value) => {
    const factor = Math.sqrt(value / maxFeatureValue);
    return {
      color: "#9cb8e4",
      clearcoat: 0.5,
      reflectivity: 0.35,
      ior: 1.3,
      transmission: factor,
      roughness: factor,
      thickness: 0.1,
    };
  };

  // 辅助方法2: 创建多边形的mesh和line
  const createPolygon = (polygon, elem) => {
    const shape = new THREE.Shape();
    const pointsArray = [];
    polygon.forEach(([x, y], i) => {
      const [projX, projY] = projection([x, y]);
      i === 0 ? shape.moveTo(projX, -projY) : shape.lineTo(projX, -projY);
      pointsArray.push(new THREE.Vector3(projX, -projY, mapDepth / 24));
    });

    const lineGeometry = new THREE.BufferGeometry().setFromPoints(pointsArray);
    const extrudeSettings = {depth: mapDepth / 24, bevelEnabled: false};
    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
    const material = new THREE.MeshPhysicalMaterial(
        getMaterialConfig(elem.properties.subFeatureIndex)
    );
    return {
      mesh: new THREE.Mesh(geometry, material),
      line: new THREE.Line(
          lineGeometry,
          new THREE.LineBasicMaterial({color: "white"})
      ),
    };
  };

  // 辅助方法3: 处理每个地图 feature
  const processFeature = (elem) => {
    const province = new THREE.Object3D();
    const {coordinates} = elem.geometry;

    if (elem.geometry.type === "MultiPolygon") {
      coordinates.forEach((multiPolygon) => {
        multiPolygon.forEach((polygon) => {
          const {mesh, line} = createPolygon(polygon, elem);
          province.add(mesh, line);
        });
      });
    } else if (elem.geometry.type === "Polygon") {
      coordinates.forEach((polygon) => {
        const {mesh, line} = createPolygon(polygon, elem);
        province.add(mesh, line);
      });
    }

    province.properties = elem.properties;
    map.add(province);
  };

  data.features.forEach((elem) => {
    processFeature(elem); // 使用 processFeature 处理每个 feature

    // 添加城市名称
    const cityName = elem.properties.name;
    const centroid = elem.properties.centroid ||
        elem.properties.center || [0, 0];
    if (centroid) map.add(createLabel(cityName, centroid, 0.01));
  });

  // 设置地图位置并添加到场景
  map.position.set(
      mapInitPosition.x,
      mapInitPosition.y,
      mapInitPosition.z + 7.5
  );
  applyDynamicMapScale(map);
  scene.add(map);
  loading.value = false;
};

// 创建中间地图
const createMidMap = (data) => {
  midMap = new THREE.Object3D();
  const projection = getProjection();

  // 材质配置
  const getMidMapMaterial = () => {
    return new THREE.MeshPhysicalMaterial({
      color: "#d2ebff",
      transmission: 1, // 模拟玻璃效果
      thickness: 0.3, // 调整厚度
      roughness: 0.6, // 控制表面粗糙度
      ior: 1, // 设置折射率
      clearcoat: 0.5, // 添加清漆效果
      clearcoatRoughness: 0.1, // 清漆粗糙度
      reflectivity: 0.35, // 反射率
    });
  };

  // 创建多边形的 mesh
  const createPolygonMesh = (polygon) => {
    const shape = new THREE.Shape();
    const pointsArray = polygon.map(([x, y], i) => {
      const [projX, projY] = projection([x, y]);
      i === 0 ? shape.moveTo(projX, -projY) : shape.lineTo(projX, -projY);
      return new THREE.Vector3(projX, -projY, mapDepth);
    });

    const geometry = new THREE.ExtrudeGeometry(shape, {
      depth: mapDepth,
      bevelEnabled: false,
    });
    return new THREE.Mesh(geometry, getMidMapMaterial());
  };

  // 遍历每个 feature 并生成 mesh
  data.features.forEach((elem) => {
    const province = new THREE.Object3D();
    const {coordinates, type} = elem.geometry;

    if (type === "MultiPolygon") {
      coordinates.forEach((multiPolygon) => {
        multiPolygon.forEach((polygon) => {
          province.add(createPolygonMesh(polygon));
        });
      });
    } else if (type === "Polygon") {
      coordinates.forEach((polygon) => {
        province.add(createPolygonMesh(polygon));
      });
    }

    province.properties = elem.properties;
    midMap.add(province);
  });

  // 设置地图位置并添加动态缩放和场景添加
  midMap.position.set(
      mapInitPosition.x,
      mapInitPosition.y,
      mapInitPosition.z + 1.5
  );
  applyDynamicMapScale(midMap);
  scene.add(midMap);
};

// 创建底部地图
const createBaseMap = (data) => {
  baseMap = new THREE.Object3D(); // 创建地图对象
  const projection = getProjection();
  const geometries = []; // 用于存储每个省份的几何体

  // 辅助函数：创建 ExtrudeGeometry 的多边形几何体
  const createExtrudeGeometry = (polygon) => {
    const shape = new THREE.Shape();
    polygon.forEach(([x, y], i) => {
      const [projX, projY] = projection([x, y]);
      i === 0 ? shape.moveTo(projX, -projY) : shape.lineTo(projX, -projY);
    });

    const extrudeSettings = {depth: mapDepth / 4, bevelEnabled: false};
    return new THREE.ExtrudeGeometry(shape, extrudeSettings);
  };

  // 遍历每个 feature 并生成几何体
  data.features.forEach((elem) => {
    const {coordinates, type} = elem.geometry;

    if (type === "MultiPolygon") {
      coordinates.forEach((multiPolygon) => {
        multiPolygon.forEach((polygon) => {
          geometries.push(createExtrudeGeometry(polygon));
        });
      });
    } else if (type === "Polygon") {
      coordinates.forEach((polygon) => {
        geometries.push(createExtrudeGeometry(polygon));
      });
    }
  });

  // 合并所有几何体
  const mergedGeometry = mergeGeometries(geometries);

  // 创建材质并加载纹理
  const matcapTexture = new THREE.TextureLoader().load(
      "http://47.105.210.118:10005/json/C7C7D7_4C4E5A_818393_6C6C74-512px.png"
  );
  const material = new THREE.MeshMatcapMaterial({matcap: matcapTexture});

  // 将合并的几何体创建为一个 Mesh 并添加到 baseMap
  const mergedMesh = new THREE.Mesh(mergedGeometry, material);
  baseMap.add(mergedMesh);

  // 设置地图位置并添加动态缩放
  baseMap.position.set(mapInitPosition.x, mapInitPosition.y, mapInitPosition.z);
  applyDynamicMapScale(baseMap);
  scene.add(baseMap); // 将地图添加到场景
};

const createLabel = (name, point, depth) => {
  const div = document.createElement("div");
  div.style.color = "#000";
  div.style.fontSize = "12px";
  div.style.textShadow = "1px 1px 2px #047cd6";
  div.textContent = name;
  const label = new CSS2DObject(div);
  label.scale.set(1, 1, 1);
  let pFn = geoMercator().center(aCoordinate).scale(scale).translate([0, 0]);
  const [x, y] = pFn(point);

  label.position.set(x, -y, depth);
  cameraModelCss2dGroup.push(label);
  return label;
};
// 设置投影函数
const getProjection = () => {
  return geoMercator().center(aCoordinate).scale(scale).translate([0, 0]);
};

// 动画循环
const animate = () => {
  if (!isAnimating.value) return;
  requestAnimationFrame(animate);
  labelRenderer.render(scene, camera);
  // lightAnimate();
  controls.update();
  renderer.render(scene, camera);
};
// 光圈逻辑
const lightAnimate = () => {
  const elapsedTime = performance.now() / 3000;
  const stage = (elapsedTime / T) % 2;

  if (stage < 1) {
    lightMaterial.uniforms.innerRadius.value =
        1.5 * Math.abs(Math.sin(elapsedTime));
  } else {
    lightMaterial.uniforms.innerRadius.value = 0;
  }

  lightMaterial.uniforms.ringWidth.value = ringWidth;
};

const handleClick = (e) => {
  if (!mouse) {
    mouse = new THREE.Vector2();
  }
  mouse.x =
      ((e.clientX - renderer.domElement.getBoundingClientRect().left) /
          renderer.domElement.clientWidth) *
      2 -
      1;
  mouse.y =
      -(
          (e.clientY - renderer.domElement.getBoundingClientRect().top) /
          renderer.domElement.clientHeight
      ) *
      2 +
      1;
  if (map) {
    lastPick = null;
    const mouseVector = new THREE.Vector2(mouse.x, mouse.y);

    // 使用点击位置进行射线检测
    raycaster.setFromCamera(mouseVector, camera);
    const intersects = raycaster.intersectObjects(scene.children, true);

    // 查找特定材质的对象
    lastPick = intersects.find(
        (item) =>
            item.object.material &&
            item.object.material.type === "MeshPhysicalMaterial" &&
            item.object.material.thickness === 0.1
    );
    console.log(lastPick);
    if (lastPick && lastPick.object?.parent?.properties?.name) {
      aCoordinate = lastPick.object?.parent?.properties?.centroid;
      scale = MapScale[lastPick.object?.parent?.properties?.level];
      if (lastPick.object?.parent?.properties?.level === "district") {
        return;
      }
      fetchMapData(lastPick.object?.parent?.properties.adcode);
      resetInitMap();
    }
  }

  controls.update(); // 更新控制器
};
// 窗口调整大小
const onWindowResize = () => {
  const width = containerRef.value.clientWidth;
  const height = containerRef.value.clientHeight;
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
};

onMounted(() => {
  isAnimating.value = true;
  labelRenderer = new CSS2DRenderer();
  initializeThree();
  window.addEventListener("resize", onWindowResize);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", onWindowResize);
  isAnimating.value = false;
  if (renderer) renderer.dispose();
  if (controls) controls.dispose();
  if (labelRenderer?.domElement?.parentNode) {
    labelRenderer.domElement.parentNode.removeChild(labelRenderer.domElement);
  }
});
</script>

<style scoped>
.map-container {
  position: relative;
}
</style>
    